import aiofiles
import os
import time
from datetime import datetime, timedelta
from typing import Annotated, Literal, Union
from uuid import UUID

import uvicorn
from fastapi import FastAPI, Path, Query, Body,Cookie,Header,status,Form,File,UploadFile
from fastapi.openapi.docs import get_swagger_ui_html, get_swagger_ui_oauth2_redirect_html, get_redoc_html
from fastapi.responses import HTMLResponse
from starlette.staticfiles import StaticFiles
from pydantic import BaseModel, Field, HttpUrl, EmailStr

# 创建FastAPI实例，禁用掉FastAPI会自动生成Swagger UI和Redoc文档
app = FastAPI(docs_url=None, redoc_url=None)

# 静态文件挂载（路由与静态文件映射）
app.mount("/static", StaticFiles(directory="../statics"), name="static")


# 重新提供一个Swagger UI，相当于我们自己重写了这么一个路由
@app.get("/docs", include_in_schema=False)
def custom_swagger_ui():
    return get_swagger_ui_html(
        openapi_url = "/openapi.json",
        title = "Swagger UI for FastAPI",
        swagger_js_url="/static/swagger-ui-bundle.min.js",
        swagger_css_url="/static/swagger-ui.min.css"
    )
@app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False)
async def swagger_ui_redirect():
    return get_swagger_ui_oauth2_redirect_html()

# 这里与Swagger UI一样，重新提供Redoc
@app.get("/redoc", include_in_schema=False)
def custom_redoc():
    return get_redoc_html(
        openapi_url = "/openapi.json",
        title = "Redoc for FastAPI",
        redoc_js_url="/static/redoc.standalone.js"
    )

@app.post("/login")
# async def login(username: Annotated[str,Form()], password: Annotated[str,Form()]):
async def login(username: str = Form(), password: str = Form()):
    return {"username": username}


class UserBean(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: str | None = None
    # 禁止多余字段
    model_config = {"extra":"forbid"}

@app.post("/user")
async def create_user(user_in: UserBean = Form()):
    return user_in


@app.post("/files")
# async def create_file(file: bytes = File()):
async def create_file(file: Annotated[bytes, File()]):
    return {"file_size": len(file)}

@app.post("/uploadfile")
async def create_upload_file(file: UploadFile):
    filename = file.filename        # 获取源文件的名称
    # 生成一个保存文件名
    save_filename = f"{filename.split('.')[0]}_{int(time.time() * 1000)}.{filename.split('.')[-1]}"
    # 把上传的文件写入这个文件中
    # 把文件写入到本地upload目录当中
    path = os.path.join("upload", save_filename)
    # 使用 os.makedirs 函数来确保目录存在，如果不存在则创建
    os.makedirs(os.path.dirname(path), exist_ok=True)
    with open(path, "wb") as f:
        while True:
            data = await file.read(8192)
            # data = file.file.read(8192)
            if not data:
                break
            f.write(data)

    print(f"保存文件 {save_filename} 成功！")
    return {"upload_file": filename, "save_file": save_filename}

@app.post("/files2")
async def read_file2(file: UploadFile | None = None):
    if not file:
        return {"message": "没有上传文件"}
    return {"filename": file.filename,
            "content": await file.read()}

@app.post("/files3")
async def read_file3(file: Annotated[bytes | None, File()] = None):
    if not file:
        return {"message": "没有上传文件"}
    else:
        return {"file_size": len(file)}


@app.post("/files4")
async def read_file4(file: UploadFile = File(description="这是一个UploadFile")):
    return {"filename": file.filename}

@app.post("/files5")
async def read_file5(file: bytes = File(description="这是一个bytes")):
    return {"file_size": len(file)}


@app.get("/")
async def main():
    content = """
<body>
<form action="/files6/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
<form action="/uploadfiles6/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
</body>   
    """
    return HTMLResponse(content=content)

@app.post("/files6")
async def create_file6(files: list[bytes] = File()):
    return {"file_sizes": [len(file) for file in files]}

@app.post("/uploadfiles6")
async def create_upload_file6(files: list[UploadFile]):
    return {"filenames": [file.filename for file in files]}


@app.post("/files7")
async def create_file7(
        files: list[bytes] = File(description="上传文件File"),
        upload_files: list[UploadFile] = File(description="上传文件UploadFile"),
        token: str = Form(description="一个token"),
):
    return {
        "file_size": [len(file) for file in files],
        "upload_files_name": [file.filename for file in upload_files],
        "token": token,
    }

if __name__ == '__main__':
    app.debug = True
    uvicorn.run("main:app", host="127.0.0.1", port=8019, reload=True)

